from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64
import json
import random
import string
from datetime import datetime, timedelta
import requests
import qrcode
from io import BytesIO
import base64 as b64

class EncryptionUtil:
    """数据加密解密工具类"""
    
    def __init__(self, key=None):
        if key:
            if isinstance(key, str):
                key = key.encode()
            # 确保密钥长度为32字节
            if len(key) < 32:
                key = key.ljust(32, b'0')
            elif len(key) > 32:
                key = key[:32]
            
            # 使用PBKDF2生成密钥
            kdf = PBKDF2HMAC(
                algorithm=hashes.SHA256(),
                length=32,
                salt=b'salt_',  # 在生产环境中应使用随机盐
                iterations=100000,
            )
            key = base64.urlsafe_b64encode(kdf.derive(key))
        else:
            key = Fernet.generate_key()
        
        self.cipher = Fernet(key)
    
    def encrypt(self, data):
        """加密数据"""
        if isinstance(data, dict):
            data = json.dumps(data)
        if isinstance(data, str):
            data = data.encode()
        
        encrypted_data = self.cipher.encrypt(data)
        return base64.urlsafe_b64encode(encrypted_data).decode()
    
    def decrypt(self, encrypted_data):
        """解密数据"""
        try:
            encrypted_data = base64.urlsafe_b64decode(encrypted_data.encode())
            decrypted_data = self.cipher.decrypt(encrypted_data)
            return decrypted_data.decode()
        except Exception as e:
            raise ValueError(f"解密失败: {str(e)}")
    
    def encrypt_json(self, data):
        """加密JSON数据"""
        return self.encrypt(json.dumps(data))
    
    def decrypt_json(self, encrypted_data):
        """解密JSON数据"""
        decrypted_str = self.decrypt(encrypted_data)
        return json.loads(decrypted_str)

class SmsUtil:
    """腾讯云短信工具类"""
    
    def __init__(self, secret_id, secret_key, app_id, sign_name, template_id, region="ap-beijing"):
        """
        初始化腾讯云短信服务
        :param secret_id: 腾讯云API密钥ID
        :param secret_key: 腾讯云API密钥Key
        :param app_id: 短信应用ID
        :param sign_name: 短信签名
        :param template_id: 短信模板ID
        :param region: 地域，默认北京
        """
        self.secret_id = secret_id
        self.secret_key = secret_key
        self.app_id = app_id
        self.sign_name = sign_name
        self.template_id = template_id
        self.region = region
        self.endpoint = "sms.tencentcloudapi.com"
    
    def generate_code(self, length=6):
        """生成验证码"""
        return ''.join(random.choices(string.digits, k=length))
    
    def _get_signature_v3(self, payload, timestamp):
        """生成腾讯云API v3.0签名"""
        import hmac
        import hashlib
        from datetime import datetime
        
        # 步骤1：拼接规范请求串
        http_request_method = "POST"
        canonical_uri = "/"
        canonical_querystring = ""
        canonical_headers = f"content-type:application/json; charset=utf-8\nhost:{self.endpoint}\n"
        signed_headers = "content-type;host"
        hashed_request_payload = hashlib.sha256(payload.encode('utf-8')).hexdigest()
        canonical_request = f"{http_request_method}\n{canonical_uri}\n{canonical_querystring}\n{canonical_headers}\n{signed_headers}\n{hashed_request_payload}"
        
        # 步骤2：拼接待签名字符串
        algorithm = "TC3-HMAC-SHA256"
        # 从timestamp获取日期
        timestamp_int = int(timestamp)
        date = datetime.utcfromtimestamp(timestamp_int).strftime('%Y-%m-%d')
        credential_scope = f"{date}/sms/tc3_request"
        hashed_canonical_request = hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()
        string_to_sign = f"{algorithm}\n{timestamp}\n{credential_scope}\n{hashed_canonical_request}"
        
        # 步骤3：计算签名
        def sign(key, msg):
            return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
        
        secret_date = sign(("TC3" + self.secret_key).encode('utf-8'), date)
        secret_service = sign(secret_date, "sms")
        secret_signing = sign(secret_service, "tc3_request")
        signature = hmac.new(secret_signing, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()
        
        return signature
    
    def send_sms(self, phone, code, expire_minutes=5):
        """
        发送短信验证码
        :param phone: 手机号（需要包含国家代码，如+86）
        :param code: 验证码
        :param expire_minutes: 验证码有效期（分钟）
        :return: (success, message)
        """
        try:
            import time
            import json
            from datetime import datetime
            
            # 确保手机号格式正确
            if not phone.startswith('+'):
                phone = '+86' + phone
            
            # 构建请求体
            timestamp = int(time.time())
            timestamp_str = str(timestamp)
            payload = {
                "PhoneNumberSet": [phone],
                "SmsSdkAppId": str(self.app_id),  # 确保App ID是字符串格式
                "SignName": self.sign_name,
                "TemplateId": str(self.template_id),  # 确保模板ID是字符串格式
                "TemplateParamSet": [code]  # 只发送验证码，不包含过期时间
            }
            payload_str = json.dumps(payload, separators=(',', ':'))
            
            # 生成签名
            signature = self._get_signature_v3(payload_str, timestamp_str)
            
            # 构建Authorization头
            date = datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%d')
            credential_scope = f"{date}/sms/tc3_request"
            authorization = f"TC3-HMAC-SHA256 Credential={self.secret_id}/{credential_scope}, SignedHeaders=content-type;host, Signature={signature}"
            
            # 发送请求
            url = f"https://{self.endpoint}/"
            headers = {
                'Authorization': authorization,
                'Content-Type': 'application/json; charset=utf-8',
                'Host': self.endpoint,
                'X-TC-Action': 'SendSms',
                'X-TC-Timestamp': timestamp_str,
                'X-TC-Version': '2021-01-11',
                'X-TC-Region': self.region
            }
            
            response = requests.post(url, data=payload_str, headers=headers)
            result = response.json()
            print(f"发送返回的 result: {str(result)}")
            if response.status_code == 200 and 'Response' in result:
                if 'Error' in result['Response']:
                    error = result['Response']['Error']
                    return False, f"发送失败: {error['Code']} - {error['Message']}"
                else:
                    print(f"✅ 短信发送成功到 {phone}: {code}")
                    return True, "发送成功"
            else:
                return False, f"请求失败: {result}"
                
        except Exception as e:
            print(f"❌ 短信发送异常: {str(e)}")
            return False, f"发送失败: {str(e)}"
    
    def send_sms_simple(self, phone, code):
        """
        简化版发送短信（用于测试）
        在开发环境中可以只打印验证码，不实际发送
        """
        try:
            # 开发环境下直接返回成功，并打印验证码
            print(f"📱 [腾讯云短信] 发送验证码到 {phone}: {code}")
            print(f"   签名: {self.sign_name}")
            print(f"   模板ID: {self.template_id}")
            return True, "发送成功（开发模式）"
        except Exception as e:
            return False, f"发送失败: {str(e)}"

class WechatUtil:
    """微信工具类"""
    
    def __init__(self, app_id, app_secret, token):
        self.app_id = app_id
        self.app_secret = app_secret
        self.token = token
        self.access_token = None
        self.access_token_expires = None
    
    def get_access_token(self):
        """获取微信访问令牌"""
        if self.access_token and self.access_token_expires and datetime.now() < self.access_token_expires:
            return self.access_token
        
        url = f"https://api.weixin.qq.com/cgi-bin/token"
        params = {
            'grant_type': 'client_credential',
            'appid': self.app_id,
            'secret': self.app_secret
        }
        
        try:
            response = requests.get(url, params=params)
            data = response.json()
            
            if 'access_token' in data:
                self.access_token = data['access_token']
                self.access_token_expires = datetime.now() + timedelta(seconds=data['expires_in'] - 300)
                return self.access_token
            else:
                raise Exception(f"获取access_token失败: {data}")
        except Exception as e:
            raise Exception(f"获取微信访问令牌失败: {str(e)}")
    
    def create_qr_code(self, scene_id, expire_seconds=600):
        """创建临时二维码"""
        access_token = self.get_access_token()
        url = f"https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={access_token}"
        
        data = {
            "expire_seconds": expire_seconds,
            "action_name": "QR_STR_SCENE",
            "action_info": {
                "scene": {
                    "scene_str": scene_id
                }
            }
        }
        
        try:
            response = requests.post(url, json=data)
            result = response.json()
            
            if 'ticket' in result:
                qr_url = f"https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={result['ticket']}"
                return result['ticket'], qr_url
            else:
                raise Exception(f"创建二维码失败: {result}")
        except Exception as e:
            raise Exception(f"创建微信二维码失败: {str(e)}")
    
    def get_user_info(self, openid):
        """获取用户信息"""
        access_token = self.get_access_token()
        url = f"https://api.weixin.qq.com/cgi-bin/user/info"
        params = {
            'access_token': access_token,
            'openid': openid,
            'lang': 'zh_CN'
        }
        
        try:
            response = requests.get(url, params=params)
            return response.json()
        except Exception as e:
            raise Exception(f"获取微信用户信息失败: {str(e)}")

class QRCodeUtil:
    """二维码工具类"""
    
    @staticmethod
    def generate_qr_code(data, size=10, border=4):
        """生成二维码"""
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=size,
            border=border,
        )
        qr.add_data(data)
        qr.make(fit=True)
        
        img = qr.make_image(fill_color="black", back_color="white")
        
        # 转换为base64
        buffer = BytesIO()
        img.save(buffer, format='PNG')
        img_str = b64.b64encode(buffer.getvalue()).decode()
        
        return f"data:image/png;base64,{img_str}"

def generate_uuid():
    """生成UUID"""
    import uuid
    return str(uuid.uuid4())

def get_client_ip(request):
    """获取客户端IP地址"""
    if request.headers.get('X-Forwarded-For'):
        return request.headers.get('X-Forwarded-For').split(',')[0].strip()
    elif request.headers.get('X-Real-IP'):
        return request.headers.get('X-Real-IP')
    else:
        return request.remote_addr

def validate_phone(phone):
    """验证手机号格式"""
    import re
    pattern = r'^1[3-9]\d{9}$'
    return re.match(pattern, phone) is not None

def validate_email(email):
    """验证邮箱格式"""
    import re
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return re.match(pattern, email) is not None